﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Windows.Forms;


namespace AttrapeMoi
{
    class Carte
    {
        private int longueur_x, longueur_y, longueur_adjacence;
        private String type_map;
        private int compte_tour;
        private bool type_actu;
        private String mode_jeu;
        private int[,] matrice_adjacence;
        private Casee[,] matrice_terrain;
        private List<Sommet> caseAdj;

        private Voleur voleur;
        private List<Gendarme> list_gendarme;

        public int Compte_tour
        {
            get { return compte_tour; }
        }

        public bool Type_actu
        {
            get { return type_actu; }
        }

        public List<Sommet> CaseAdj
        {
            get { return caseAdj; }
            set { caseAdj = value; }
        }

        public Vector2 Voleur
        {
            get { return voleur.Position; }
        }

        public List<Gendarme> List_Gendarme
        {
            get { return list_gendarme; }
        }

        public Casee[,] Matrice_terrain
        {
            get { return matrice_terrain; }
        }

        public int[,] Matrice_adjacence
        {
            get { return matrice_adjacence; }
        }
        
        public int Longueur_adjacence
        {
            get { return longueur_adjacence; }
        }

        public int Longueur_y
        {
            get { return longueur_y; }
        }

        public int Longueur_x
        {
            get { return longueur_x; }
        }


        public Casee getCase(int x, int y)
        {
            return matrice_terrain[y, x];
        }

        public Casee getCase(float x, float y)
        {
            return matrice_terrain[(int)y, (int)x];
        }

        public Casee getCase(Vector2 XY)
        {
            return matrice_terrain[(int)XY.Y, (int)XY.X];
        }

        public Casee getCase(int numCase)
        {     
            return getCase(convertNumToXY(numCase));
        }

        public Carte(string type_graphe, String mode_jeu)
        {
            this.mode_jeu = mode_jeu;
            compte_tour = 0;
            type_actu = true;
            type_map = type_graphe;
            if (type_graphe == "classique")
            {
                longueur_x = 8;
                longueur_y = 8;
                longueur_adjacence = longueur_x * longueur_y;
                matrice_adjacence = new int[longueur_adjacence, longueur_adjacence];
                matrice_terrain = new Casee[longueur_y, longueur_x];
                for (int i = 0; i < longueur_adjacence; i++)
                {
                    for (int j = 0; j < longueur_adjacence; j++)
                    {
                        if ((j == i + 1 && i % longueur_y != longueur_y-1) || (i == j + 1 && j % longueur_x != longueur_x-1))
                            matrice_adjacence[i, j] = 1;

                        if (j == longueur_x + i || i == longueur_y + j)
                            matrice_adjacence[i, j] = 1;
                    }
                }    
            }
            else if (type_graphe == "tore")
            {
                longueur_x = 8;
                longueur_y = 8;
                longueur_adjacence = longueur_x * longueur_y;
                matrice_adjacence = new int[longueur_adjacence, longueur_adjacence];
                matrice_terrain = new Casee[longueur_y, longueur_x];
                for (int i = 0; i < longueur_adjacence; i++)
                {
                    for (int j = 0; j < longueur_adjacence; j++)
                    {
                        if ((j == i + 1 && i % longueur_y != longueur_y - 1) || (i == j + 1 && j % longueur_x != longueur_x - 1))
                            matrice_adjacence[i, j] = 1;

                        if ((i % longueur_y == 0 && j == i+7) || (j % longueur_x == 0 && i ==j+ 7))
                            matrice_adjacence[i, j] = 1;

                        if (j == longueur_x + i || i == longueur_y + j)
                            matrice_adjacence[i, j] = 1;

                        if (j == longueur_x*(longueur_y-1) + i || i == longueur_y*(longueur_x-1) + j)
                            matrice_adjacence[i, j] = 1;
                    }
                }
            }
            else if (type_graphe == "hypercube 3")
            {
                longueur_adjacence = 8;
                longueur_x = 2;
                longueur_y = 4;
                matrice_adjacence = new int[longueur_adjacence, longueur_adjacence];
                matrice_terrain = new Casee[longueur_y, longueur_x];
                for (int i = 0; i < longueur_adjacence; i++)
                    for (int j = 0; j < longueur_adjacence; j++)
                        matrice_adjacence[i, j] = 0;

                matrice_adjacence[0, 1] = 1;
                matrice_adjacence[0, 2] = 1;
                matrice_adjacence[0, 4] = 1;

                matrice_adjacence[1, 0] = 1;
                matrice_adjacence[1, 3] = 1;
                matrice_adjacence[1, 5] = 1;

                matrice_adjacence[2, 0] = 1;
                matrice_adjacence[2, 3] = 1;
                matrice_adjacence[2, 6] = 1;

                matrice_adjacence[3, 1] = 1;
                matrice_adjacence[3, 2] = 1;
                matrice_adjacence[3, 7] = 1;

                matrice_adjacence[4, 0] = 1;
                matrice_adjacence[4, 5] = 1;
                matrice_adjacence[4, 6] = 1;

                matrice_adjacence[5, 1] = 1;
                matrice_adjacence[5, 4] = 1;
                matrice_adjacence[5, 7] = 1;

                matrice_adjacence[6, 2] = 1;
                matrice_adjacence[6, 4] = 1;
                matrice_adjacence[6, 7] = 1;

                matrice_adjacence[7, 3] = 1;
                matrice_adjacence[7, 5] = 1;
                matrice_adjacence[7, 6] = 1;
            }
            else if (type_graphe == "hypercube 4")
            {
                longueur_x = 4;
                longueur_y = 4;
                longueur_adjacence = 16;
                matrice_adjacence = new int[longueur_adjacence, longueur_adjacence];
                matrice_terrain = new Casee[longueur_y, longueur_x];
                for (int i = 0; i < longueur_adjacence; i++)
                    for (int j = 0; j < longueur_adjacence; j++)
                        matrice_adjacence[i, j] = 0;

                for (int i = 0; i < 7; i++)
                {
                    matrice_adjacence[i, i + 1] = 1;
                    matrice_adjacence[i + 1, i] = 1;

                    matrice_adjacence[i, i + 7] = 1;
                    matrice_adjacence[i + 7, i] = 1;

                    matrice_adjacence[i, i + 9] = 1;
                    matrice_adjacence[i + 9, i] = 1;
                }

                matrice_adjacence[7, 14] = 1;
                matrice_adjacence[8, 15] = 0;
                matrice_adjacence[15, 8] = 0;
                matrice_adjacence[14, 7] = 1;

                for (int i = 8; i < 11; i++)
                {
                    matrice_adjacence[i, i + 3] = 1;
                    matrice_adjacence[i + 3, i] = 1;

                    matrice_adjacence[i, i + 5] = 1;
                    matrice_adjacence[i + 5, i] = 1;
                }

                matrice_adjacence[11, 14] = 1;
                matrice_adjacence[14, 11] = 1;

                matrice_adjacence[12, 15] = 1;
                matrice_adjacence[15, 12] = 1;

                matrice_adjacence[0, 15] = 1;
                matrice_adjacence[15, 0] = 1;
            }

            for (int i = 0; i < longueur_y; i++)
                for (int j = 0; j < longueur_x; j++)
                {
                    matrice_terrain[i, j] = new Casee();
                    matrice_terrain[i, j].Initialize(j, i, convertXYToNum(j, i));
                }
        }
        public int placeDepart()
        {
            Random aleatoire = new Random();
            int a, b, n;

            a = aleatoire.Next(longueur_x);
            b = aleatoire.Next(longueur_y);

            switch (type_map)
            {
                case "classique":
                    n = 2;
                    break;
                    
                case "hypercube 3":
                    n = 2;
                    break;

                case "hypercube 4":
                    n = 2;
                    break;

                case "tore":
                    n = 2;
                    break;

                default:
                    n = 1;     
                    break;

            }

            voleur = new Voleur(a, b);
            matrice_terrain[b, a].Contenu1 = Contenu.voleur;

            list_gendarme = new List<Gendarme>();
            for (int i = 0; i < n; i++)
            {
                a = aleatoire.Next(longueur_x);
                b = aleatoire.Next(longueur_y);
                if (matrice_terrain[b, a].Contenu1 != Contenu.vide)
                    i--;
                else
                {
                    list_gendarme.Add(new Gendarme(a, b));

                    matrice_terrain[b, a].Contenu1 = Contenu.gendarme;
                }
            }

            return n;
        }

        public virtual void LoadContent(ContentManager content)
        {
            for (int i = 0; i < longueur_y; i++)
                for (int j = 0; j < longueur_x; j++)
                {
                    matrice_terrain[i, j].LoadContent(content);
                }
        }

        public virtual void Update(MouseState souris)
        {
            int pers_actu = compte_tour % list_gendarme.Count;

            if (type_actu)
            {
                if (mode_jeu == "duel")
                {
                    if (souris.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        Vector2 posSouris = Vector2.Zero;
                        int x_cal = 0, y_cal = 0, num_case = 0;
                        switch(type_map)
                        {
                            case "classique":
                            case "tore":
                                posSouris = new Vector2((int)(souris.X / 21), (int)(souris.Y / 21));
                                break;

                            case "hypercube 3":
                                
                                for (int i = 0; i <= 6; i += 2)
                                {
                                    if (souris.X > i * 20 && souris.X < (i + 1) * 20)
                                        x_cal = i;

                                    if (souris.Y > i * 20 && souris.Y < (i + 1) * 20)
                                        y_cal = i;
                                }
                                switch (x_cal)
                                {
                                    case 0:
                                        switch (y_cal)
                                        {
                                            case 0:
                                                num_case = 4;
                                                break;

                                            case 6:
                                                num_case = 6;
                                                break;
                                        }
                                        break;

                                    case 2:
                                        switch (y_cal)
                                        {
                                            case 2:
                                                num_case = 0;
                                                break;

                                            case 4:
                                                num_case = 2;
                                                break;
                                        }
                                        break;

                                    case 4:
                                        switch (y_cal)
                                        {
                                            case 1:
                                                num_case = 0;
                                                break;

                                            case 3:
                                                num_case = 2;
                                                break;
                                        }
                                        break;

                                    case 6:
                                        switch (y_cal)
                                        {
                                            case 0:
                                                num_case = 5;
                                                break;

                                            case 6:
                                                num_case = 7;
                                                break;
                                        }
                                        break;
                                }
                                posSouris = convertNumToXY(num_case);
                                break;

                            case "hypercube 4":
                                for (int i = 0; i <= 8; i++)
                                {
                                    if (souris.X > i * 20 && souris.X < (i + 1) * 20)
                                        x_cal = i;

                                    if (souris.Y > i * 20 && souris.Y < (i + 1) * 20)
                                        y_cal = i;
                                }
                                switch (x_cal)
                                {
                                    case 0:
                                        if (y_cal == 4)
                                            num_case = 6;
                                        break;

                                    case 1:
                                        switch (y_cal)
                                        {
                                            case 1:
                                                num_case = 7;
                                                break;

                                            case 7:
                                                num_case = 5;
                                                break;
                                        }
                                        break;

                                    case 2:
                                        if (y_cal == 4)
                                            num_case = 14;
                                        break;

                                    case 3:
                                        switch (y_cal)
                                        {
                                            case 3:
                                                num_case = 15;
                                                break;

                                            case 5:
                                                num_case = 13;
                                                break;
                                        }
                                        break;

                                    case 4:
                                        switch (y_cal)
                                        {
                                            case 0:
                                                num_case = 0;
                                                break;
                                                
                                            case 2:
                                                num_case = 8;
                                                break;

                                            case 6:
                                                num_case = 12;
                                                break;

                                            case 8:
                                                num_case = 4;
                                                break;
                                        }
                                        break;

                                    case 5:
                                        switch (y_cal)
                                        {
                                            case 3:
                                                num_case = 9;
                                                break;

                                            case 5:
                                                num_case = 11;
                                                break;
                                        }
                                        break;

                                    case 6:
                                        if (y_cal == 4)
                                            num_case = 10;
                                        break;

                                    case 7:
                                        switch (y_cal)
                                        {
                                            case 1:
                                                num_case = 1;
                                                break;

                                            case 7:
                                                num_case = 3;
                                                break;
                                        }
                                        break;

                                    case 8:
                                        if (y_cal == 4)
                                            num_case = 2;
                                        break;
                                }
                                posSouris = convertNumToXY(num_case);
                                break;
                                
                        }

                        foreach (Sommet s in caseAdj)
                        {
                            if (s.Pred.X == posSouris.X && s.Pred.Y == posSouris.Y && matrice_terrain[s.Pred.Y, s.Pred.X].Contenu1 != Contenu.gendarme)
                            {
                                getCase(voleur.Position).Contenu1 = Contenu.vide;
                                voleur.Position = posSouris;
                                getCase(voleur.Position).Contenu1 = Contenu.voleur;
                            }
                        }

                        if (voleur.Position != posSouris)
                            type_actu = !type_actu;
                    }
                    else
                        type_actu = !type_actu;

                }
                else
                    voleur.calculer_nouvelle_position(this);
            }
            else
            {
                Gendarme ga = list_gendarme[pers_actu];
                foreach (Gendarme g in list_gendarme)
                {
                    Vector2 v1 = (g.Position - voleur.Position), v2 = (ga.Position - voleur.Position);
                    float va = (v1.X*v1.X + v1.Y*v1.Y), vb = (v2.X*v2.X + v2.Y*v2.Y);
                    if (va < vb && g.Ancienne_position != Djikstra.Direction1(g.Position, voleur.Position, this))
                        ga = g;
                    else if (g.Ancienne_position == Djikstra.Direction1(g.Position, voleur.Position, this))
                        g.Ancienne_position = Vector2.Zero;
                }
                
                ga.calculer_nouvelle_position(this);
                compte_tour++;
            }
            voleur.DirectionIntelligente(this);

            type_actu = !type_actu;
        }

        public virtual void Draw(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
        {
            for (int i = 0; i < longueur_y; i++)
                for (int j = 0; j < longueur_x; j++)
                {
                    matrice_terrain[i, j].Draw(spriteBatch, type_map);

                    if (caseAdj != null)
                    {
                        foreach (Sommet s in caseAdj)
                        {
                            if (s.Pred.X == j && s.Pred.Y == i && matrice_terrain[i, j].Contenu1 != Contenu.gendarme)
                            {
                                Texture2D tex = new Texture2D(graphicsDevice, 20, 20, true, SurfaceFormat.Color);
                                Color[] couleur = new Color[400];
                                for (int k = 0; k < couleur.Length; k++)
                                {
                                    couleur[k] = new Color(255 - 25 * s.Potentiel, 0, s.Potentiel * 25);
                                }
                                tex.SetData(couleur);
                                matrice_terrain[i, j].DrawSpecialTexture(tex, type_map, spriteBatch);
                            }
                        }
                    }
                }
        }

        public Vector2 convertNumToXY(int num)
        {
            return new Vector2(num % longueur_x, num / longueur_x);
        }

        public int convertXYToNum(int x, int y)
        {
            return x + y * longueur_x;
        }
    }
}
